package sas

import (
	"fmt"
	"strings"
	"time"

	"gitee.com/micro-plat/sas/sas/modules/const/enum"
	"github.com/micro-plat/lib4go/security/rsa"
	"github.com/micro-plat/lib4go/types"
)

//Dynamic 动态签名和加密方法(不能把动态密钥设置为加密字段-否则会造成失败)
//input 签名和加密参数
//dynamicKey 动态key(用户自行生成,sdk会使用配置对应的rsa公钥进行加密传输)
//signType 签名类型:md5,sha1,sha256,sha512,hmac(使用上面的动态key进行签名)
//encryptType 加密类型:aes,des(使用动态key进行数据加密)
//mode 指定加密模式  例:aes加密时:CFB/pkca5   des加密时:CBC/pkca5
func (n *sasClient) Dynamic(input types.XMap, dynamicKey, signType, encryptType string, mode ...string) (sign string, data types.XMap, err error) {
	//签名和加密类型检查
	if err = n.checkType(signType, encryptType, enum.Dynamic); err != nil {
		return
	}

	if encryptType == DESStr && len(dynamicKey) != 8 {
		err = fmt.Errorf("dynamic-des加密密钥长度必须=8,currt length %d", len(dynamicKey))
		return
	}

	//获取加密后的动态密钥
	edynamicKey, err := n.getDynamicKey(dynamicKey)
	if err != nil {
		return
	}

	input.SetValue(n.getDynamicKeyName(), edynamicKey)
	input.SetValue(n.getTimespanName(), time.Now().Format("20060102150405"))
	input.SetValue(n.getEUIDName(), n.euid)
	encryptMap := types.XMap{}
	encryptMap, err = n.dynamicEncrypt(input, encryptType, dynamicKey, mode...)
	if err != nil {
		return
	}

	return n.dynamicSign(encryptMap, signType, dynamicKey)
}

//获取动态key
func (n *sasClient) getDynamicKey(dynamicKey string) (key string, err error) {
	//获取密钥
	res, err := n.SecretGet(RSAStr)
	if err != nil {
		return "", err
	}

	return rsa.Encrypt(dynamicKey, res.RsaPublicSecret, strings.ToUpper(res.PkcsType))
}

func (n *sasClient) dynamicSign(input types.XMap, signType, dynamicKey string) (sign string, data types.XMap, err error) {
	switch signType {
	case MD5Str:
		return n.md5SignKey(input, dynamicKey)
	case SHA1Str:
		return n.sha1SignKey(input, dynamicKey)
	case SHA256Str:
		return n.sha256SignKey(input, dynamicKey)
	case SHA512Str:
		return n.sha512SignKey(input, dynamicKey)
	case HMACStr:
		return n.hmacSignKey(input, dynamicKey)
	}

	return
}

func (n *sasClient) dynamicEncrypt(input types.XMap, encryptType, dynamicKey string, mode ...string) (data types.XMap, err error) {
	data = types.XMap{}
	switch encryptType {
	case AESStr:
		return n.aesEncrypt(input, dynamicKey, mode...)
	case DESStr:
		return n.desEncrypt(input, dynamicKey, mode...)
	}
	return
}
